---
layout: docs
page_title: Terminating Gateways - Kubernetes
sidebar_title: Terminating Gateways
description: Configuring Terminating Gateways on Kubernetes
---

# Terminating Gateways on Kubernetes

-> 1.8.0+: This feature is available in Consul versions 1.8.0 and higher

-> 0.16.0+: This feature is available in consul-k8s versions 0.16.0 and higher

~> This topic requires familiarity with [Terminating Gateways](/docs/connect/terminating-gateway).

Terminating gateways are a new feature included in Consul 1.8. The correlating consul-k8s binary version is
[0.16.0](https://github.com/hashicorp/consul-k8s/blob/master/CHANGELOG.md#0160-june-17-2020), and is required to enable
terminating gateways. If you are using the latest official [consul-helm chart](https://github.com/hashicorp/consul-helm),
and have not customized the [imageK8S](/docs/k8s/helm#v-global-imagek8s) configuration for any of
your components, you should be running a compatible version by default.

Adding a terminating gateway is a multi-step process:

- Update the helm chart with terminating gateway config options
- Deploying the helm chart
- Accessing the Consul agent
- Register external services with Consul

## Update the helm chart with terminating gateway config options

Minimum required Helm options:

```yaml
global:
  name: consul
connectInject:
  enabled: true
terminatingGateways:
  enabled: true
```

## Deploying the helm chart

Ensure you have the latest consul-helm chart and install Consul via helm using the following
[guide](/docs/k8s/installation#installing-consul) while being sure to provide the yaml configuration
as previously discussed.

## Accessing the Consul agent

You can access the Consul server directly from your host via `kubectl port-forward`. This is helpful for interacting with your Consul UI locally as well as to validate connectivity of the application.

```shell-session
$ kubectl port-foward consul-server-0 8500 &
```

If TLS is enabled use port 8501:

```shell-session
$ kubectl port-foward consul-server-0 8501 &
```

-> Be sure the latest consul binary is installed locally on your host.
[https://releases.hashicorp.com/consul/](https://releases.hashicorp.com/consul/)

```shell-session
$ export CONSUL_HTTP_ADDR=http://localhost:8500
```

If TLS is enabled set:

```shell-session
$ export CONSUL_HTTP_ADDR=https://localhost:8501
$ export CONSUL_HTTP_SSL_VERIFY=false
```

If ACLs are enabled also set:

```shell-session
$ export CONSUL_HTTP_TOKEN=$(kubectl get secret consul-bootstrap-acl-token -o jsonpath={.data.token} | base64 -D)
```

## Register external services with Consul

Registering the external services with Consul is a multi-step process:

- Register external services with Consul
- Update the terminating gateway ACL token if ACLs are enabled
- Create the configuration entry for the terminating gateway
- Create intentions to allow access from services in the mesh to external service
- Define upstream annotations for any services that need to talk to the external services

### Register external services with Consul

Create a sample external service and register it with Consul.

```json
{
  "Node": "legacy_node",
  "Address": "example.com",
  "NodeMeta": {
    "external-node": "true",
    "external-probe": "true"
  },
  "Service": {
    "ID": "example-https",
    "Service": "example-https",
    "Port": 443
  }
}
```

Register the external service with Consul:

```shell-session
$ curl --request PUT --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
```

If ACLs and TLS are enabled :

```shell-session
$ curl --request PUT --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
```

### Update terminating gateway ACL token if ACLs are enabled

If ACLs are enabled, update the terminating gateway acl token to have `service: write` permissions on all of the services
being represented by the gateway:

- Create a new policy that includes these permissions
- Update the existing token to include the new policy

~> The CLI command should be run with the `-merge-policies`, `-merge-roles` and `-merge-service-identities` so
nothing is removed from the terminating gateway token

```hcl
service "example-https" {
  policy = "write"
}
```

```shell-session
$ consul acl policy create -name "example-https-write-policy" -rules @write-policy.hcl
```

Now fetch the id of the terminating gateway token

```shell-session
$ consul acl token list | grep terminating-gateway-terminating-gateway-token
```

Update the terminating gateway acl token with the new policy

```shell-session
$ consul acl token update -id <token-id> -policy-name example-https-write-policy -merge-policies -merge-roles -merge-service-identities
```

### Create the configuration entry for the terminating gateway

Once the tokens have been updated, next write the Consul [config](/docs/agent/config-entries/terminating-gateway)
entry for the terminating gateway:

```hcl
Kind = "terminating-gateway"
Name = "terminating-gateway"
Services = [
 {
   Name = "example-https"
   CAFile = "/etc/ssl/cert.pem"
 }
]
```

~> If TLS is enabled a `CAFile` must be provided, it must point to the system trust store of the terminating gateway
container.

Submit the terminating gateway entry with the Consul CLI using this command.

```shell-session
$ consul config write terminating-gateway.hcl
```

If using ACLs and TLS, create intentions to allow access from services in the mesh to the external service

```shell-session
$ consul intention create -allow static-client example-https
```

### Define the external services as upstreams for services in the mesh

Finally define and deploy the external services as upstreams for the internal mesh services that wish to talk to them.
An example deployment is provided which will serve as a static client for the terminating gateway service.

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: static-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: static-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: static-client
  template:
    metadata:
      name: static-client
      labels:
        app: static-client
      annotations:
        'consul.hashicorp.com/connect-inject': 'true'
        'consul.hashicorp.com/connect-service-upstreams': 'example-https:1234'
    spec:
      containers:
        # This name will be the service name in Consul.
        - name: static-client
          image: tutum/curl:latest
          command: ['/bin/sh', '-c', '--']
          args: ['while true; do sleep 30; done;']
        # If ACLs are enabled, the serviceAccountName must match the Consul service name.
      serviceAccountName: static-client
```

Run the service via `kubectl apply`:

```shell-session
$ kubectl apply -f static-client.yaml
```

You can verify connectivity of the static-client and terminating gateway via a curl command:

```shell-session
$ kubectl exec deploy/static-client -- curl -vvvs -H "Host: example-https.com" http://localhost:1234/
```
